#include "glog/logging.h"
#include "slam/io/text_file_read_write.h"

namespace slam {
namespace io {

bool LoadDataFromTxt(const std::string& file_name,
    const std::string& delimiter,
    std::vector<std::vector<std::string>>* all_str_ptr) {
  std::fstream txt_file(file_name, std::fstream::in);
  if (!txt_file.is_open()) {
    LOG(WARNING) << "File reader: Open txt file failed!";
    return false;
  }

  std::vector<std::string> line_str;
  std::string line;
  while(getline(txt_file,line)){
    line_str.push_back(line);
  }
  txt_file.close();

  if (line_str.empty()) {
    LOG(ERROR) << "File reader: Empty txt file!";
    return false;
  }
  auto& all_str = *all_str_ptr;
  all_str.clear();

  for (const auto& item : line_str) {
    std::vector<std::string> result;
    SplitString(item, delimiter, &result);
    all_str.emplace_back(result);
  }
  if (all_str.empty()) {
    LOG(ERROR) << "File reader: Empty file: " << file_name;
    return false;
  }

  return true;
}

void SplitString(const std::string& str, const std::string& delimiter,
    std::vector<std::string>* result){
  std::string::size_type pos;
  auto& split_result = *result;
  split_result.clear();
  const auto split_str = str + delimiter;
  const int size = split_str.size();
  for (int i = 0; i < size; i++) {
    pos = split_str.find(delimiter, i);
    if (pos < size) {
      std::string s = split_str.substr(i, pos - i);
      split_result.push_back(s);
      i = pos + delimiter.size() - 1;
    }
  }
}

bool LoadNavigationNodeFromJson(const std::string& file_name,
      std::vector<std::vector<std::string>>* navigation_node_ptr) {
  Json::Value root;
  if (!LoadDataFromJson(file_name, &root)) {
    LOG(ERROR) << "File reader: Read navi node json file failed!";
    return false;
  }
  
  auto& all_node_str = *navigation_node_ptr;
  all_node_str.clear();
   if (root.isMember("vertices")) {
    const int node_num = root["vertices"].size();
    if (node_num > 0) {
      all_node_str.reserve(node_num);
      for (int index = 0; index < node_num; index++) {
        std::vector<std::string> one_node;
        one_node.emplace_back(root["vertices"][index]["id"].asString());
        one_node.emplace_back(root["vertices"][index]["type"].asString());
        one_node.emplace_back(root["vertices"][index]["x"].asString());
        one_node.emplace_back(root["vertices"][index]["y"].asString());
        one_node.emplace_back(root["vertices"][index]["yaw"].asString());
        all_node_str.emplace_back(one_node);
      }
      return true;
    }
  }
  return false;
}

bool LoadNavigationEdgeFromJson(const std::string& file_name,
      std::vector<std::vector<std::string>>* navigation_edge_ptr) {
  Json::Value root;
  if (!LoadDataFromJson(file_name, &root)) {
    LOG(ERROR) << "File reader: Read navi node json file failed!";
    return false;
  }
  
  auto& all_edge_str = *navigation_edge_ptr;
  all_edge_str.clear();

  if (root.isMember("edges")) {
    const int edge_num = root["edges"].size();
    if (edge_num > 0) {
      all_edge_str.reserve(edge_num);
      for (int index = 0; index < edge_num; index++) {
        std::vector<std::string> one_edge;
        one_edge.emplace_back(root["edges"][index]["vertex1_id"].asString());
        one_edge.emplace_back(root["edges"][index]["vertex2_id"].asString());
        all_edge_str.emplace_back(one_edge);
      }
      return true;
    }
  }
  return false;
}

bool LoadDataFromJson(const std::string& file_name,
    Json::Value* data) {
  std::ifstream ifs(file_name);
  if (!ifs.is_open()) {
    LOG(WARNING) << "Json file open failed: " << file_name;
    return false;
  }
  auto& root = *data;
  Json::CharReaderBuilder read_builder;
  JSONCPP_STRING errs;
  if (!parseFromStream(read_builder, ifs, &root, &errs)) {
    LOG(WARNING) << "Json file parse failed: " << file_name;
    return false;
  }
  return true;
}

}
}